home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / skim-0.8 / skim-0 / skim-0.8.4 / GetSubjectsOfNewArticlesInGroup.c < prev    next >
C/C++ Source or Header  |  1996-02-18  |  8KB  |  284 lines

  1. /*
  2.  * NAME
  3.  *   GetSubjectsOfNewArticlesInGroup.c
  4.  * USAGE
  5.  *   GetSubjectsOfNewArticlesInGroup GroupName
  6.  * DESCRIPTION
  7.  *   Retrieve the header lines (Author, Lines, Subject) from the NNTP server
  8.  *   for all articles in group `GroupName' starting with article number 
  9.  *   `FromArticleNumber'.
  10.  * IMPLEMENTATION NOTES
  11.  *   The algorithm is:
  12.  *
  13.  *       - Send the XOVER command to the NNTP server.
  14.  *        
  15.  *             This step is in  main() in this file.
  16.  *
  17.  *       - Receive and convert header lines.
  18.  *
  19.  *             This step is in ConvertOverviewToHeaderLine() in this file.
  20.  *
  21.  *       - Match with AutoSelect and Kill patterns.
  22.  *
  23.  *             This step is in ASAKExecute() in AutoSelectAndKill.c.
  24.  *
  25.  *       - Merge the lines which were not killed with the existing contents
  26.  *         of the Subjects file.
  27.  *
  28.  *             This step is in ASAKClose() in AutoSelectAndKill.c.
  29.  *
  30.  *       - Sort the lines by subject, ignoring the "Re: " prefix (pseudo
  31.  *         threading).
  32.  *
  33.  *             This step is in ASAKClose() in AutoSelectAndKill.c.
  34.  *
  35.  *       - Write the result to the Subjects file.
  36.  *
  37.  *             This step is in ASAKClose() in AutoSelectAndKill.c.
  38.  * COPYRIGHT
  39.  *   Skim - Off-line news reading package optimized for slow lines.
  40.  *   Copyright (C) 1996  Rene W.J. Pijlman
  41.  *
  42.  *   This program is free software; you can redistribute it and/or modify
  43.  *   it under the terms of the GNU General Public License as published by
  44.  *   the Free Software Foundation; either version 2 of the License, or
  45.  *   (at your option) any later version.
  46.  * 
  47.  *   This program is distributed in the hope that it will be useful,
  48.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  49.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  50.  *   GNU General Public License for more details.
  51.  *
  52.  *   You should have received a copy of the GNU General Public License
  53.  *   along with this program; if not, write to the Free Software
  54.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  55.  * VERSION
  56.  *   Skim version 0.8.4.
  57.  */
  58.  
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include <unistd.h>
  62. #include <assert.h>
  63.  
  64. #include "MemAlloc.h"
  65. #include "Skim.h"
  66. #include "NNTPStream.h"
  67. #include "SkimUtils.h"
  68. #include "AutoSelectAndKill.h"
  69. #include "ArticleNumber.h"
  70. #include "StandardIO.h"
  71.  
  72.  
  73. FILE_ID("$Header: /home/rene/sys/CVS_MasterSourceRepository/skim/GetSubjectsOfNewArticlesInGroup.c,v 1.7 1996/02/17 22:47:31 rene Exp $");
  74.  
  75. #define HEADER_SUBJECT "Subject"
  76. #define HEADER_FROM    "From"
  77. #define HEADER_LINES   "Lines"
  78.  
  79. static int OverviewOffsetArticleNumber = 0;
  80. static int OverviewFmtOffsetSubject  = 0;
  81. static int OverviewFmtOffsetFrom     = 0;
  82. static int OverviewFmtOffsetLines    = 0;
  83.  
  84. const char InputSeparator = '\t';
  85.  
  86. const char Overflow = '*';
  87.  
  88.  
  89. static void FixSizeOfLinesField( VarBuf Target )
  90. {
  91.     if ( VBSize(Target) > LengthOfNumberOfLines() )
  92.     {
  93.         int i;
  94.  
  95.         VBReset( Target );
  96.  
  97.         for ( i = 0; i < LengthOfNumberOfLines(); i++ )
  98.         {
  99.         VBAppendCharacter( Target, Overflow );
  100.         }
  101.     }
  102.     else
  103.     {
  104.     VBShiftRight( Target, LengthOfNumberOfLines() - VBSize( Target ), 
  105.                   PadCharacter );
  106.     }
  107.  
  108.     assert( VBSize( Target ) == LengthOfNumberOfLines() );
  109. }
  110.  
  111. static void MissingFieldError( char * Field )
  112. {
  113.     SIOPrintf( StandardError,
  114.     "The `%s' field is missing in the overview from the news server.\n",
  115.         Field );
  116.     exit( EXIT_FAILURE );
  117. }
  118.  
  119. static void ConvertOverviewToHeaderLine( VarBuf Target )
  120. {
  121.     VarBuf Overview = VBCreate();
  122.  
  123.     VBAppendVB( Overview, Target );
  124.     VBReset( Target );
  125.  
  126.     VBAppendCharacter( Target, NotSelected );
  127.  
  128.     VBFixSize( Target, OffsetOfArticleNumber() - 1, PadCharacter );
  129.     VBAppendCharacter( Target, PadCharacter );
  130.  
  131.     /* Append article number. */
  132.     if ( !AppendFieldFromSeparatorRecord( Target, Overview, InputSeparator,
  133.                                  OverviewOffsetArticleNumber, NULL ) )
  134.     {
  135.         MissingFieldError( "Article number" );
  136.     }
  137.  
  138.     VBFixSize( Target, OffsetOfAuthor() - 1, PadCharacter );
  139.     VBAppendCharacter( Target, PadCharacter );
  140.  
  141.     /* Append author. */
  142.     if ( !AppendFieldFromSeparatorRecord( Target, Overview, InputSeparator, 
  143.                                  OverviewFmtOffsetFrom, AuthorFromFromField ) )
  144.     {
  145.         MissingFieldError( "From" );
  146.     }
  147.  
  148.     VBFixSize( Target, OffsetOfLines() - 1, PadCharacter );
  149.     VBAppendCharacter( Target, PadCharacter );
  150.  
  151.     /* Append number of lines, if available in the overview database. */
  152.     if ( OverviewFmtOffsetLines > 0 )
  153.     {
  154.         if ( !AppendFieldFromSeparatorRecord( Target, Overview, InputSeparator,
  155.                                      OverviewFmtOffsetLines, 
  156.                                      FixSizeOfLinesField ) )
  157.         {
  158.             MissingFieldError( "Lines" );
  159.         }
  160.     }
  161.  
  162.     VBFixSize( Target, OffsetOfSubject() - 1, PadCharacter );
  163.     VBAppendCharacter( Target, PadCharacter );
  164.  
  165.     /* Append subject. */
  166.     if ( !AppendFieldFromSeparatorRecord( Target, Overview, InputSeparator, 
  167.                                  OverviewFmtOffsetSubject, NULL ) )
  168.     {
  169.         MissingFieldError( "Subject" );
  170.     }
  171.  
  172.     VBDestroy( Overview );
  173. }
  174.  
  175.  
  176. /* Determine the offset of a field in the overview. */
  177. static void InterpretOverviewFmt( VarBuf Line )
  178. {
  179.     static int OverviewFmtCounter = 0;
  180.  
  181.     OverviewFmtCounter++;
  182.  
  183.     if ( !strncasecmp( VBAsString( Line ), HEADER_SUBJECT, 
  184.                        strlen(HEADER_SUBJECT) ) )
  185.     {
  186.         OverviewFmtOffsetSubject = OverviewFmtCounter;
  187.     }
  188.     else if ( !strncasecmp( VBAsString( Line ), HEADER_FROM, 
  189.                             strlen(HEADER_FROM) ) )
  190.     {
  191.         OverviewFmtOffsetFrom = OverviewFmtCounter;
  192.     }
  193.     else if ( !strncasecmp( VBAsString( Line ), HEADER_LINES, 
  194.                             strlen(HEADER_LINES) ) )
  195.     {
  196.         OverviewFmtOffsetLines = OverviewFmtCounter;
  197.     }
  198. }
  199.  
  200.  
  201. static const char * NeedXover =
  202. "Skim: the news server returned an error when skim issued the \"list\n\
  203. overview.fmt\" or the \"XOVER\" command. Perhaps your news server doesn't\n\
  204. support these NNTP extensions. Skim needs these commands for access to the\n\
  205. News OverView (NOV) database. This is becoming a defacto standard for\n\
  206. efficiently accessing header information via NNTP. Check with your ISP or\n\
  207. news administrator. When the news server doesn't support the NOV database\n\
  208. skim is of no use to you. Sorry.\n";
  209.  
  210.  
  211. int main( int argc, char **argv )
  212. {
  213.     VarBuf Command = VBCreate();
  214.  
  215.     StandardIO NewsServer;
  216.  
  217.     if ( argc != 2 )
  218.     {
  219.         SIOPrintf( StandardError, "%s\n",
  220.                        "Usage: GetSubjectsOfNewArticlesInGroup GroupName" );
  221.         exit( EXIT_FAILURE );
  222.     }
  223.  
  224.     if ( strlen(argv[1]) > 0 )
  225.     {
  226.     /* Open standard I/O stream to NNTP server. */
  227.     NewsServer = NNTPStreamOpen();
  228.  
  229.     SIOInternetCommand( NewsServer, "list overview.fmt" );
  230.     CheckStatusResponse( NewsServer, argv[1], "215", NeedXover, 
  231.                  TERMINATE_ON_ERROR );
  232.  
  233.     GetTextResponse( NewsServer, InterpretOverviewFmt, NULL, NULL, NULL );
  234.  
  235.     if ( OverviewFmtOffsetSubject == 0 || OverviewFmtOffsetFrom == 0 )
  236.     {
  237.         SIOPrintf( StandardError,
  238.  
  239.     "The overview database of your news server does not contain the `%s'\n"
  240.     "header line.\n", OverviewFmtOffsetSubject == 0 ? "Subject" : "From" );
  241.  
  242.         exit( EXIT_FAILURE );
  243.     }
  244.  
  245.     /* Make group current. */
  246.     VBReset( Command );
  247.     VBPrintf( Command, "group %s", argv[1] );
  248.     SIOInternetCommand( NewsServer, VBAsString( Command ) );
  249.     CheckStatusResponse( NewsServer, argv[1], "2", NULL, TERMINATE_ON_ERROR );
  250.  
  251.     /*
  252.      * Retrieve the subject lines.
  253.      *
  254.      * Note: the xover command is not part of the NNTP protocol in RFC-977.
  255.      * The RFC does allow extensions, however, and I think many servers do 
  256.      * support the xover command. When in doubt, query your NNTP server:
  257.      *
  258.      *   telnet $NNTPSERVER 119
  259.      *   help
  260.      *       ...
  261.      *       XOVER   ...
  262.      *   quit
  263.      */
  264.     VBReset( Command );
  265.     VBPrintf( Command, "xover %lu-", GetCurrentArticleNumber(argv[1]) );
  266.     SIOInternetCommand( NewsServer, VBAsString( Command ) );
  267.     CheckStatusResponse( NewsServer, argv[1], "2",
  268.                  NeedXover, TERMINATE_ON_ERROR );
  269.  
  270.     ASAKOpen( argv[1] );
  271.  
  272.     GetTextResponse( NewsServer, ConvertOverviewToHeaderLine,
  273.              NULL, NULL, ASAKExecute );
  274.  
  275.     NNTPStreamClose( NewsServer );
  276.  
  277.     ASAKClose();
  278.     }
  279.  
  280.     VBDestroy( Command );
  281.  
  282.     return EXIT_SUCCESS;
  283. }
  284.